package com.vcc.boss.core.interceptor;


import cn.dev33.satoken.annotation.SaCheckLogin;
import com.alibaba.fastjson2.JSONObject;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.vcc.boss.core.component.AliIpComponent;
import com.vcc.boss.core.config.AccountConfig;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.*;
import com.vcc.data.entity.User;
import com.vcc.data.entity.WhiteLabel;
import com.vcc.service.sa.BossUserUtil;
import com.vcc.service.service.BossUserService;
import com.vcc.service.service.IpInfoService;
import com.vcc.service.service.RoleService;
import com.vcc.core.exception.SignInException;
import com.vcc.data.entity.BossUser;
import com.vcc.service.service.WhiteLabelService;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Component
@Log4j2
public class AuthInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);

    @Autowired
    private BossUserService bossUserService;
    @Autowired
    private WhiteLabelService whiteLabelService;
    @Value("${spring.profiles.active:dev}")
    private String activeProfile;

    private static final Cache<String, JSONObject> cache = Caffeine.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if ("OPTIONS".equals(request.getMethod())) {
            return true;
        }

        log.info("请求路径: {}, 请求方法: {}, 请求IP: {}",
                request.getRequestURI(),
                request.getMethod(),
                IpUtil.getIp(request));
        String source = request.getHeader("source");
        String host = request.getHeader("host");
        String uri = request.getRequestURI();
        System.out.println("source = " + source);
        System.out.println("host = " + host);
        if (StringUtils.isNotBlank(source)) {
            //正式环境下判断域名是否绑定
            //先检查缓存内是否存在，不存在的话再去数据库查询，如果存在其中则放行，不存在就检查内置状态是否为true,true则放行，false则抛出异常
            if (activeProfile.equals("prod") && !"boss.allwincard.com".equals(source)) {
                JSONObject tempCheck = cache.get(source, key -> {
                    Boolean exists = whiteLabelService.existsByAdminDomain(source);
                    if (!exists) {
                        return JSONObject.of(
                                "exists", false
                        );
                    }
                    WhiteLabel whiteLabel = whiteLabelService.getByAdminDomain(source);
                    return JSONObject.of(
                            "exists", true,
                            "status", whiteLabel.getStatus()
                    );
                });
                if (!tempCheck.getBoolean("exists")) {
                    throw new ProgramException("当前域名未绑定，无法使用");
                }
                if (tempCheck.getInteger("status") == null || !tempCheck.getInteger("status").equals(0)) {
                    throw new ProgramException("当前域名未审核通过，无法使用");
                }
            }
        } else {
            //判断路径是不是包含 llMessage || photonPayMessage || emailNotification
            //当前路径为放行路径 外部通知结构
            if (uri.startsWith("/message/")) {
                //放行
                return true;
            } else {
                throw new ProgramException("请求头缺少source参数，请联系管理员");
            }
        }
        try {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            SaCheckLogin userAuthenticate = method.getAnnotation(SaCheckLogin.class);
            //如果没有加注解则userAuthenticate为null
            if (Objects.nonNull(userAuthenticate)) {
                BossUser user = BossUserUtil.get();
                //判断访问host的父级Id是不是当前用户的父级id
                Integer status = bossUserService.getStatusById(user.getId());
                if (user.getParentId() != null && user.getParentId() > 0) {
                    // 如果有父级用户，则检查父级用户状态
                    Integer parentStatus = bossUserService.getStatusById(user.getParentId());
                    if (parentStatus == null || !parentStatus.equals(0)) {
                        logger.info("用户ID: {}, 父级用户ID: {}, 状态: {},账号状态异常，提出登录", user.getId(), user.getParentId(), parentStatus);
                        bossUserService.updateStatusById(user.getId(), parentStatus);
                        throw new SignInException("主账户状态异常，请联系管理员");
                    }
                }
                logger.info("用户ID: {}, 状态: {}", user.getId(), status);
                if (status == null || status < 0) {
                    logger.info("用户ID: {}, 状态: {},账号状态异常，提出登录", user.getId(), status);
                    throw new SignInException("请重新登录");
                }
                // 0 可用 1 禁用  2  管理员禁用 3  注销
                if (status == 1) {
                    logger.info("用户ID: {}, 状态: {},账号状态禁用，提出登录", user.getId(), status);
                    throw new SignInException("账号已被禁用");
                }
            }
            return true;
        } catch (Exception e) {
            logger.error("报错", e);
            throw e instanceof SignInException ? e : new SignInException("请重新登录");
        }
    }
}
